Vous apprendrez aujourd'hui comment interagir avec les fichiers: les lire et y récupérer des données, puis y écrire pour produire un fichier de log par exemple.
Écrire dans un fichier n'est pas très compliquée. Il y a en effet un applet de commande prévu justement pour envoyer dans un fichier ce qu'il reçoit en entrée: out-file. Par exemple, essayez:
get-process | out-file -filepath processus.txt
Notez qu'il n'est pas obligatoire d'écrire le -filepath, le premier paramètre est toujours considéré comme étant le chemin vers le fichier de destination:
get-process | out-file processus.txt
Si on veut faire changer le format du tout, il faut faire attention. Ceci ne donne pas les résultats escomptés:
get-process | out-file processus.txt | format-list
En effet, out-file ne produit pas de sortie, il envoie les données dans un fichier. Les données provenant de get-process seront donc envoyées dans processus.txt sous la forme de tableau par défaut et rien n'atteindra format-list. Il faut plutôt faire ainsi:
get-process | format-list | out-file processus.txt
Si on désire écrire du texte dans un fichier (plutôt que d'envoyer le résultat d'une commande), on ne peut pas faire non plus:
write-host Tôt ce matin partons aux framboises | out-file paroles.txt
Ceci créera bel et bien un fichier appelé paroles.txt, mais il sera vide! L'explication est simple: write-host envoie les données à la console et non pas dans le pipeline. Encore une fois, rien n'atteindra out-file. Mais pas d'inquiétude! PowerShell est plein de ressources et un applet de commande a été prévu pour ça! Il suffit d'utiliser write-output plutôt que write-host. write-output n'envoie pas le texte directement à la console, mais il l'envoie plutôt dans le pipeline vers la prochaine commande. (Notez que si write-output est la dernière commande, la sortie sera automatiquement redirigée à la console de toute façon.)
write-output Allons calmer toute notre faim | out-file paroles.txt -append
Notez au passage le paramètre -append de out-file qui ajoute à la fin plutôt que d'écraser (le comportement par défaut). Notez également que rien n'atteint la console cette fois-ci!
Si vous regardez le fichier ainsi obtenu, vous constaterez qu'il ressemble à ceci:
Allons calmer toute notre faim
write-output envoie un mot à la fois dans le pipeline, ce qui produit un fichier avec un mot par ligne... La solution? Utilisez les guillemets:
write-output "Puisqu'est venu mon invité splendide" | out-file paroles.txt -append
Cette fois-ci, tout se retrouve bel et bien sur la même ligne.
Et pour vous simplifier encore plus la vie, l'alias write est créé par défaut et pointe vers write-output!
Lire dans un fichier n'est pas beaucoup plus compliqué, en fin de compte. Il existe un applet de commande qui lit un fichier et retourne son contenu: get-content. Son paramètre -path permet de spécifier un fichier à lire. Supposons un fichier a.txt qui contient le texte suivant:
allo toi le jeune comment vas-tu Un deux un deux patate poil Il était un petit navire
La commande suivante va lire le fichier et écrit son contenu à l'écran:
get-content -path a.txt
C'est bien joli, mais si tout ce qu'on peut faire est d'afficher le fichier à l'écran, on aurait aussi bien pu ouvrir le fichier dans le bloc-notes... Bien entendu, ça ne s'arrête pas là! On peut très bien envoyer le contenu dans une variable avec une simple assignation:
$fichier = get-content -path a.txt
Du coup, on peut regarder le contenu de la variable:
$fichier
On remarque que c'est le contenu complet du fichier, les quatre lignes l'une en dessous de l'autre. Ça ressemble étrangement à une variable de type "tableau", comme lorsque l'on fait:
$variable=1, 2, 3, 4
On peut donc tester ceci pour voir:
$fichier[1]
La deuxième ligne nous apparaît, confirmant qu'effectivement la variable contient un tableau, avec une ligne dans chaque case. Merveilleux! Pourquoi? Parce que qui dit tableau dit foreach! On pourra donc aisément parcourir le contenu du fichier une ligne à la fois:
$fichier = get-content -path a.txt $compteurLigne = 1 foreach ($ligne in $fichier) { write-host Ligne $compteurLigne : write-host $ligne $compteurLigne++ }
Ce qui serait encore plus intéressant, ça serait de pouvoir accéder au contenu mot par mot... Ça permettrait assez facilement de stocker une petite base de données dans un fichier (un enregistrement par ligne, un champ après l'autre, séparés par des espaces). Pour ce faire, rien de plus simple: notre $fichier[0] est en fait un string. Un string dans l'environnement .NET contient tout un tas de méthodes pratiques pour le manipuler. Celle qui nous intéresse ici est split. On lui passe un caractère devant être considéré comme un séparateur et le string se sépare en différents mots, qui nous sont encore une fois retournés sous forme de tableau. On peut donc utiliser un autre foreach (à l'intérieur du premier) pour passer à travers tous les mots de chaque ligne :
$fichier = get-content -path a.txt $compteurLigne = 1 foreach ($ligne in $fichier) { write-host Ligne $compteurLigne : $mots = $ligne.split(" ") $compteurMot = 1 foreach ($mot in $mots) { write-host " Mot $compteurMot : $mot" $compteurMot++ } $compteurLigne++ }Observons maintenant le résultat pour la ligne 2:
Mot 1: comment Mot 2: vas-tuÉvidemment, comme le split sépare les mots à partir des espaces, "vas-tu" est considéré comme un seul mot. Toutefois, il est possible de passer à split un tableau de séparateurs qui seront tous utilisés. On pourrait modifier notre script afin de séparer aussi avec des "-":
$fichier = get-content -path a.txt $separateurs = " ", "-" $compteurLigne = 1 foreach ($ligne in $fichier) { write-host Ligne $compteurLigne : $mots = $ligne.split($separateurs) $compteurMot = 1 foreach ($mot in $mots) { write-host " Mot $compteurMot : $mot" $compteurMot++ } $compteurLigne++ }Il est possible de mettre autant de séparateurs que désiré dans une variable.
Deux exercices
Voyez les solutions de ces exercices ici.
1- Créez un petit bottin téléphonique dans un fichier texte, en utilisant le format suivant:
Prénom Nom Numéro_de_téléphone Prénom Nom Numéro_de_téléphone ...Pour éviter les problèmes, assurez-vous que les prénoms, les noms de famille et les numéros ne contiennent pas d'espaces. Entrez quelques enregistrements fictifs (au moins 4).
Créez ensuite un script qui demande à l'usager d'entrer un prénom, puis un nom (deux demandes séparées). Le script doit aller lire votre fichier de bottin et trouver l'entrée qui correspond. S'il la trouve, il doit afficher le numéro correspondant. S'il ne la trouve pas, il doit afficher un message indiquant que l'entrée est introuvable.
Vous aurez besoin pour y arriver de vous inspirer de mon exemple ci-haut. Voici la méthode que je vous suggère:
Pour vous simplifier la vie, supposez qu'il n'y aura jamais deux noms identiques dans le bottin.
2- Bonus - Créez un script qui éliminera un nom de votre bottin! Il devra demander lui aussi un nom et un prénom à l'usager, puis il recréera le fichier de bottin en omettant la ligne correspondant aux informations données, l'éliminant ainsi du bottin.
Le fonctionnement sera très similaire au numéro 1. La seule différence sera à l'étape 3.3: si les valeurs ne correspondent pas, on réécrit la ligne dans le fichier. Si elles correspondent, on ne fait rien.
Faites bien attention: la première ligne que vous réécrivez devra écraser le fichier original, mais toutes les autres devront ajouter des lignes à la fin! Du coup, il serait sans doute une bonne idée de se créer une variable pour savoir si on est en train d'écrire la première ligne ou non...